/*
 * Copyright (C) 2012 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.example.android.apis.app;

import android.app.Activity;
import android.app.Service;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.RemoteException;
import android.os.IBinder;
import android.os.RemoteCallbackList;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.TextView;

// Need the following import to get access to the app resources, since this
// class is in a sub-package.
import com.example.android.apis.R;

/**
 * This is an example if implementing a Service that uses
 * android:isolatedProcess.
 */
public class IsolatedService extends Service {
	/**
	 * This is a list of callbacks that have been registered with the service.
	 * Note that this is package scoped (instead of private) so that it can be
	 * accessed more efficiently from inner classes.
	 */
	final RemoteCallbackList<IRemoteServiceCallback> mCallbacks = new RemoteCallbackList<IRemoteServiceCallback>();

	int mValue = 0;

	private String TAG;

	@Override
	public void onCreate() {
		TAG = getClass().getSimpleName();

		Log.i(TAG, "Creating IsolatedService: " + this);
	}

	@Override
	@Deprecated
	public void onStart(Intent intent, int startId) {
		Log.d(TAG, "onStart()");
		super.onStart(intent, startId);
	}

	@Override
	public int onStartCommand(Intent intent, int flags, int startId) {
		Log.d(TAG, "onStartCommand(" + intent + ", " + flags + ", " + startId
				+ ")");
		return super.onStartCommand(intent, flags, startId);
	}

	@Override
	public boolean onUnbind(Intent intent) {
		Log.d(TAG, "onUnbind(" + intent + ")");
		return super.onUnbind(intent);
	}

	@Override
	public void onRebind(Intent intent) {
		Log.d(TAG, "onRebind(" + intent + ")");
		super.onRebind(intent);
	}

	@Override
	public void onDestroy() {
		Log.i(TAG, "Destroying IsolatedService: " + this);
		// Unregister all callbacks.
		mCallbacks.kill();
	}

	@Override
	public IBinder onBind(Intent intent) {
		Log.i(TAG, "onBind()");
		return mBinder;
	}

	/**
	 * The IRemoteInterface is defined through IDL
	 */
	private final IRemoteService.Stub mBinder = new IRemoteService.Stub() {
		public void registerCallback(IRemoteServiceCallback cb) {
			if (cb != null)
				mCallbacks.register(cb);
		}

		public void unregisterCallback(IRemoteServiceCallback cb) {
			if (cb != null)
				mCallbacks.unregister(cb);
		}
	};

	@Override
	public void onTaskRemoved(Intent rootIntent) {
		Log.i(TAG, "Task removed in " + this + ": " + rootIntent);
		stopSelf();
	}

	private void broadcastValue(int value) {
		// Broadcast to all clients the new value.
		final int N = mCallbacks.beginBroadcast();
		for (int i = 0; i < N; i++) {
			try {
				mCallbacks.getBroadcastItem(i).valueChanged(value);
			} catch (RemoteException e) {
				// The RemoteCallbackList will take care of removing
				// the dead object for us.
			}
		}
		mCallbacks.finishBroadcast();
	}

	// ----------------------------------------------------------------------

	public static class Controller extends Activity {
		static class ServiceInfo {
			final Activity mActivity;
			final Class<?> mClz;
			final TextView mStatus;
			boolean mServiceBound;
			IRemoteService mService;
			final String TAG = "ServiceInfo";

			ServiceInfo(Activity activity, Class<?> clz, int start, int stop,
					int bind, int status) {
				mActivity = activity;
				mClz = clz;
				Button button = (Button) mActivity.findViewById(start);
				button.setOnClickListener(mStartListener);
				button = (Button) mActivity.findViewById(stop);
				button.setOnClickListener(mStopListener);
				CheckBox cb = (CheckBox) mActivity.findViewById(bind);
				cb.setOnClickListener(mBindListener);
				mStatus = (TextView) mActivity.findViewById(status);
			}

			void destroy() {
				Log.d(TAG, "destroy()");
				if (mServiceBound) {
					mActivity.unbindService(mConnection);
				}
			}

			private OnClickListener mStartListener = new OnClickListener() {
				public void onClick(View v) {
					mActivity.startService(new Intent(mActivity, mClz));
				}
			};

			private OnClickListener mStopListener = new OnClickListener() {
				public void onClick(View v) {
					mActivity.stopService(new Intent(mActivity, mClz));
				}
			};

			private OnClickListener mBindListener = new OnClickListener() {
				public void onClick(View v) {
					if (((CheckBox) v).isChecked()) {
						if (!mServiceBound) {
							if (mActivity.bindService(new Intent(mActivity,
									mClz), mConnection,
									Context.BIND_AUTO_CREATE)) {
								mServiceBound = true;
								mStatus.setText("BOUND");
							}
						}
					} else {
						if (mServiceBound) {
							mActivity.unbindService(mConnection);
							mServiceBound = false;
							mStatus.setText("");
						}
					}
				}
			};

			private ServiceConnection mConnection = new ServiceConnection() {
				public void onServiceConnected(ComponentName className,
						IBinder service) {
					mService = IRemoteService.Stub.asInterface(service);
					if (mServiceBound) {
						mStatus.setText("CONNECTED");
					}
				}

				public void onServiceDisconnected(ComponentName className) {
					// This is called when the connection with the service has
					// been
					// unexpectedly disconnected -- that is, its process
					// crashed.
					mService = null;
					if (mServiceBound) {
						mStatus.setText("DISCONNECTED");
					}
				}
			};
		}

		ServiceInfo mService1;
		ServiceInfo mService2;

		@Override
		protected void onCreate(Bundle savedInstanceState) {
			super.onCreate(savedInstanceState);

			setContentView(R.layout.isolated_service_controller);

			mService1 = new ServiceInfo(this, IsolatedService.class,
					R.id.start1, R.id.stop1, R.id.bind1, R.id.status1);
			mService2 = new ServiceInfo(this, IsolatedService2.class,
					R.id.start2, R.id.stop2, R.id.bind2, R.id.status2);
		}

		@Override
		protected void onDestroy() {
			super.onDestroy();
			mService1.destroy();
			mService2.destroy();
		}
	}
}
